﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json.Serialization;
using Sharp.DataTransferObject;
using Sharp.Platform;
using Sharp.Platform.Mvc;
using Sharp.Platform.Interface;
using Sharp.Platform.List;
using Sharp.Platform.Mvc.Attribute;
using ColumnAttribute = Sharp.Platform.ColumnAttribute;

namespace Sharp.WebBooter
{
    /// <summary>
    /// ExtNet模板适配器
    /// </summary>
    public class BSTemplateProvider : ITemplateProvider
    {
        #region 新增
        /// <summary>
        /// 新增
        /// </summary>
        /// <returns></returns>
        public string Create(object model)
        {
            if (model == null)
            {
                return string.Empty;
            }
            StringBuilder sb = new StringBuilder();

            Rendering(sb, model, "添加");

            return sb.ToString();
        }
        #endregion

        #region 编辑
        /// <summary>
        /// 编辑
        /// </summary>
        /// <returns></returns>
        public string Edit(object model)
        {
            if (model == null)
            {
                return string.Empty;
            }
            StringBuilder sb = new StringBuilder();

            Rendering(sb, model, "修改");

            return sb.ToString();
        }
        #endregion

        #region 详情
        /// <summary>
        /// 详情
        /// </summary>
        /// <returns></returns>
        public string Details(object model)
        {
            if (model == null)
            {
                return string.Empty;
            }
            StringBuilder sb = new StringBuilder();
            Rendering(sb, model, "详情");
            return sb.ToString();
        }
        #endregion

        #region 主页
        /// <summary>
        /// 主页
        /// </summary>
        /// <returns></returns>
        public string Index(object model)
        {
            if (model == null)
            {
                return string.Empty;
            }

            if (model is ISharpTreeList)
            {
                return IndexTree(model);
            }

            var dataList = (ISharpList)model;
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("@model {0}\r\n", model.GetType().FullName);

            sb.AppendLine("@using Sharp.WebBooter");


            sb.AppendLine("<section class=\"content-header\">");

            sb.AppendLine("<h1>");

            sb.Append(dataList.GetTitle());
            sb.Append("</h1>");


            sb.AppendLine("<ol class=\"breadcrumb\">");
            sb.AppendLine("<li><a href =\"@Url.Action(\"Index\", \"Home\")\"><i class=\"fa fa-home\"></i> 首页</a></li>");
            sb.AppendLine("<li class=\"active\">VIU</li>");
            sb.AppendLine("</ol>");
            sb.AppendLine("</section>");
            sb.AppendLine("<section class=\"content\">");
            sb.AppendLine("<div class=\"row\">");
            sb.AppendLine("<div class=\"col-lg-12\">");
            sb.AppendLine("<div class=\"box box-primary\">");
            sb.AppendLine("<div class=\"box-header with-border\">");

            if (!dataList.Feature.HasFlag(ListFeature.HiddenToolButton))
            {
                sb.AppendLine("<div class=\"dataTable-tools btn-group\">");

                //渲染工具栏按钮
                var toolButtons = string.Join("\r\n", dataList.GetToolButtons(model).Select(x => x.Html));
                sb.AppendLine(toolButtons);
                sb.AppendLine("</div>");
            }


            sb.AppendLine("<div class=\"box-tools SearchArea\">");
            sb.AppendLine("<div class=\"input-group input-group-sm\" style=\"width:150px;float:right;\">");

            foreach (var column in GetColumnInfos(model))
            {
                if (column.Value.SearchFor)
                {
                    sb.AppendFormat("<input type =\"text\" name=\"{0}\" class=\"form-control pull-right\" placeholder=\"{1}\">\r\n", column.Key, column.Value.Text);
                }


            }
            sb.AppendLine("<div class=\"input-group-btn\">");
            sb.AppendLine("<button type =\"button\" class=\"btn btn-default\" onclick=\"window.app.search();\"><i class=\"fa fa-search\"></i></button>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("<div class=\"box-body no-padding\">");


            sb.AppendLine("<div class=\"table-responsive\">");
            sb.AppendLine("<table id =\"dataList\" class=\"table table-bordered table-condensed table-striped table-hover dataTable text-center\" width=\"100%\"></table>");
            sb.AppendLine("</div>");

            sb.AppendLine("</div>");
            sb.AppendLine("</div>");


            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</section>");



            sb.AppendLine("<script type=\"text/javascript\">");
            sb.AppendLine("$(document).ready(function () {");

            sb.AppendLine("$('#dataList').dataTable({");
            sb.AppendLine("\"serverSide\": true,");
            sb.AppendLine("\"ajax\": { \"url\": \"@Url.Action(\"GetPaged\")\", \"type\": \"POST\" },");
            sb.AppendLine("\"columnDefs\": [ { sDefaultContent: '', aTargets: ['_all'] },");
            sb.AppendLine("{ \"searchable\": false, sortable: false, \"orderable\": false, \"targets\": [-1, 0, 1, 2] },");
            sb.AppendLine("{ \"sClass\": \"editableCol\", \"aTargets\": [1] } ],");
            sb.AppendLine("columns: [");

            if (dataList.Feature.HasFlag(ListFeature.MultiSelect))
            {
                sb.AppendLine("{ title: '<label class=\"checkbox i-checks\"><input type=\"checkbox\" /><i></i></label>', data: function (row, type, set) { return '<label class=\"checkbox i-checks\"><input type=\"checkbox\" name=\"cellCheckbox\" value=\"' + row.id + '\" /><i></i></label>'; }, \"bStorable\": false, width: 30 ,class:'checkColumn'},");
            }
            if (dataList.Feature.HasFlag(ListFeature.RowNumber))
            {
                sb.AppendLine(
                    "{ title:'序号',data : null, bSortable : false, targets : 0, width : 50 ,class:'rowNumberColumn',render : function(data, type, row, meta) { var startIndex = meta.settings._iDisplayStart; return startIndex + meta.row + 1; }},");
            }
            CamelCasePropertyNamesContractResolver cpncr = new CamelCasePropertyNamesContractResolver();
            foreach (var column in GetColumnInfos(model))
            {

                List<string> plist = new List<string>();
                plist.Add("title: \"" + column.Value.Text + "\"");

                if (column.Value is DateColumnAttribute
                    && !((DateColumnAttribute)column.Value).Format.IsNullOrEmpty())
                {
                    plist.Add("data: function (row) { return new Date(row." + cpncr.GetResolvedPropertyName(column.Key) + ").format('" + ((DateColumnAttribute)column.Value).Format + "') }");
                }
                else
                {
                    plist.Add("data: \"" + cpncr.GetResolvedPropertyName(column.Key) + "\"");
                }
                if (column.Value.Width > 0)
                    plist.Add("width: " + column.Value.Width + "");

                sb.AppendFormat("{{ {0}}},", string.Join(",", plist.ToArray()));
            }


            //sb.AppendLine("{ title: \"名称\", data: function (row) { return '<a data-toggle=\"ajaxModal\" class=\"auto\" href=\"@Url.Action(\"Edit\")/' + row.id + '\">' + row.name + '</a>';  }, width: 160 },");

            sb.AppendLine("]");
            sb.AppendLine("});");
            sb.AppendLine("});");


            sb.AppendLine("</script>");

            return sb.ToString();
        }

        private string IndexTree(object model)
        {
            var dataList = (ISharpList)model;
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("@model {0}\r\n", model.GetType().FullName);
            sb.AppendLine("@using Ext.Net");
            sb.AppendLine("@using Ext.Net.MVC");
            sb.AppendLine("@using Sharp.WebBooter");
            sb.AppendLine("@{");
            sb.AppendLine("    var x = Html.X();");
            sb.AppendLine("}");

            sb.AppendLine("@(");
            sb.AppendLine(" x.TreePanel().UseArrows(false).AutoScroll(true).Mode(TreePanelMode.Remote).RootVisible(false).Border(false).RootVisible(false).Animate(false).FolderSort(false)");
            if (!dataList.Feature.HasFlag(ListFeature.HiddenToolButton))
            {
                sb.AppendLine("            .TopBar(x.Toolbar().Items(");

                //渲染工具栏按钮
                sb.AppendLine(string.Join(",", dataList.GetToolButtons(model).Select(x => x.Html)));

            }

            sb.AppendLine("            .Features(");
            sb.AppendLine("                x.GridFilters()");
            sb.AppendLine("                    .Local(false)");
            sb.AppendLine("                    .Filters(");
            List<string> filters = new List<string>();
            foreach (var property in model.GetType().GetProperties())
            {
                if (property.PropertyType != typeof(string))
                {
                    continue;
                }
                filters.Add("x.StringFilter().DataIndex(Model, d => d." + property.Name + ")");
            }
            sb.AppendLine(string.Join(",\r\n", filters.ToArray()));
            sb.AppendLine("                    )");
            sb.AppendLine("            )");


            sb.AppendLine("            .Store(x.StoreForModel()");
            sb.AppendLine(
                "                .Proxy(x.AjaxProxy().Url(Url.Action(\"GetPaged\")).Post().Reader(x.JsonReader().Root(\"data\")))");
            if (dataList.Feature.HasFlag(ListFeature.Paging))
            {
                sb.AppendLine("                .RemoteSort(true).RemotePaging(true).PageSize(25)");
            }


            sb.AppendLine("                .SorterFor(Model, m => m.Id, Ext.Net.SortDirection.DESC)");
            sb.AppendLine("                )");
            if (dataList.Feature.HasFlag(ListFeature.MultiSelect))
            {
                sb.AppendLine("            .SelectionModel(x.CheckboxSelectionModel())");
            }
            sb.AppendLine("            .ColumnModel(");


            List<string> columns = new List<string>();
            if (dataList.Feature.HasFlag(ListFeature.RowNumber))
            {
                columns.Add("x.RowNumbererColumn().Align(ColumnAlign.End).Width(60)");
            }
            foreach (var property in model.GetType().GetProperties())
            {
                if (!property.GetCustomAttributes(false).Any()) { continue; }
                if (property.PropertyType == typeof(MasterDataDTO))
                {
                    #region 主数据显示
                    var template =

                            property.GetCustomAttributes(typeof(TemplateColumnAttribute), false).FirstOrDefault() as TemplateColumnAttribute;
                    if (template == null)
                    {
                        var column = property.GetCustomAttributes(typeof(ColumnAttribute), false).FirstOrDefault() as ColumnAttribute;
                        var text = property.Name;
                        if (column != null)
                        {
                            text = column.Text;
                        }
                        columns.Add(
                            string.Format(
                                "x.TemplateColumn().DataIndex(\"{0}\").Text(\"{1}\").TemplateString(\"<tpl for=\\\".\\\">{{{0}.Name}}</tpl>\")",
                                property.Name, text));
                    }
                    else
                    {
                        columns.Add(
                            string.Format(
                                "x.TemplateColumn().DataIndex(\"{0}\").Text(\"{1}\").TemplateString(\"<tpl for=\\\".\\\">{{{0}.Name}}</tpl>\")",
                                property.Name, template.Text));
                    }

                    #endregion
                }
                else
                {
                    columns.Add("x.ColumnFor(m => m." + property.Name + ")");
                }
            }
            sb.AppendLine(string.Join(",\r\n", columns.ToArray()));
            sb.AppendLine("            )");
            if (dataList.Feature.HasFlag(ListFeature.Paging))
            {
                sb.AppendLine("            .BottomBar(x.PagingToolbar().ItemsFromPartial(\"~/Views/Shared/_PagingToolbarPartial.cshtml\"))");
            }
            sb.AppendLine("            .EmptyText(\"无数据。\")");
            sb.AppendFormat("            .View(x.GridView().StripeRows({0}).TrackOver(true))", (!dataList.Feature.HasFlag(ListFeature.GridLineDisable)).ToString().ToLower());
            sb.AppendLine("            .Listeners(li => { li.ItemDblClick.Fn = \"App.Grid.OnModuleGridItemDblClick\"; })");
            sb.AppendLine(")");
            return sb.ToString();
        }
        #endregion

        #region 渲染界面

        /// <summary>
        /// 渲染界面
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="model"></param>
        /// <param name="title"></param>
        private void Rendering(StringBuilder sb, object model, string title)
        {
            sb.AppendFormat("@model {0}\r\n", model.GetType().FullName);

            sb.AppendLine("<div class=\"modal\">");
            sb.AppendLine("<div class=\"modal-dialog\">");
            sb.AppendLine("<div class=\"modal-content animated flipInY\">");
            sb.AppendLine("<div class=\"modal-header\">");
            sb.AppendLine("<button type=\"button\" class=\"close\" data-dismiss=\"modal\">");
            sb.Append("<span aria-hidden=\"true\"> &times; </span>");
            sb.AppendLine("<span class=\"sr-only\"> 关闭 </span></button>");
            sb.AppendLine("<h4 class=\"modal-title\" id=\"myModalLabel\"> @Model.PageTitle </h4>");
            sb.AppendLine("</div>");

            sb.AppendLine("<div class=\"modal-body\" id=\"modalcontent\">");
            sb.AppendLine("@using(Html.Bootstrap().BeginForm(c => c.Horizontal()))");
            sb.AppendLine("{");
            sb.AppendLine("@Html.ValidationSummary()");
            sb.AppendLine("@Html.HiddenFor(x => x.Id)");

            RendingEditing(sb, model);

            sb.AppendLine("}");
            sb.AppendLine("</div>");

            sb.AppendLine("<div class=\"modal-footer\">");
            sb.AppendLine("@Html.Bootstrap().Button(\"保存\").Style(BootstrapStyle.Primary).Click(\"window.app.saveForm(event,'\" + @Url.Action(\"Save\") + \"');\")");
            sb.AppendLine(
                "@Html.Bootstrap().Button(\"关闭\").Style(BootstrapStyle.Default).Attribute(\"data-dismiss\", \"modal\")");

            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");


            //ISharpForm from = model as ISharpForm;
            //if (from == null)
            //{
            //    //sb.AppendLine("            .Width(720)");
            //}
            //else
            //{
            //    //sb.AppendFormat("            .Width({0})", from.UI.Width);
            //}

        }

        private void RendingEditing(StringBuilder sb, object model)
        {
            bool fieldInserted = false;
            foreach (var property in model.GetType().GetProperties())
            {
                var customAttributes = property.GetCustomAttributes(false);
                if (!customAttributes.Any())
                {
                    continue;
                }
                if (customAttributes.Any(x => x is DataTypeAttribute))
                {
                    var dataType = customAttributes.First(x => x is DataTypeAttribute) as DataTypeAttribute;

                    if (dataType.DataType == DataType.Html)
                    {
                        sb.AppendLine("<div class=\"form-group\">");
                        sb.Append("@Html.LabelFor(m => m." + property.Name +
                                  ", new { @class = \"col-sm-2 control-label\" })");
                        sb.AppendLine("<div class=\"col-sm-10\">");
                        sb.Append("<textarea id=\"editor\" type=\"text\" cols=\"4\">@Model." + property.Name +
                                  "</textarea>");
                        sb.AppendLine("@Html.HiddenFor(m => m." + property.Name + ")");
                        sb.Append("</div>");
                        sb.AppendLine("</div>");
                        sb.AppendLine("<script type=\"text/javascript\">");
                        sb.AppendLine("$(\"#editor\").summernote({");
                        sb.AppendLine("            height: 250,");
                        sb.AppendLine("            lang: 'zh-CN',");
                        sb.AppendLine("            callbacks: {");
                        sb.AppendLine("                onKeyup: function () {");
                        sb.AppendLine("                    var content = $(\"#editor\").summernote(\"code\");");
                        sb.AppendLine("                    $(\"#" + property.Name + "\").val(content);");
                        sb.AppendLine("                },");
                        sb.AppendLine("                onblur: function (e) {");
                        sb.AppendLine("                    var content = $(\"#editor\").summernote(\"code\");");
                        sb.AppendLine("                    $(\"#" + property.Name + "\").val(content);");
                        sb.AppendLine("                }");
                        sb.AppendLine("            }");
                        sb.AppendLine("        });</script>");
                    }
                    else if (dataType.DataType == DataType.Upload)
                    {
                        //sb.AppendFormat("x.FileUploadField().DataIndex(\"{0}\").Text(\"{1}\").ColumnWidth(1).Padding(4),", property.Name, "");
                    }
                    else if (dataType.DataType == DataType.Date)
                    {
                        sb.AppendLine("<div class=\"form-group\">");
                        sb.Append("@Html.LabelFor(m => m." + property.Name +
                                  ", new { @class = \"col-sm-2 control-label\" })");
                        sb.AppendLine("<div class=\"col-sm-10\">");
                        sb.Append("@Html.Bootstrap().DateFor(m => m." + property.Name + ")");
                        sb.Append("</div>");
                        sb.AppendLine("</div>");
                    }
                    else if (dataType.DataType == DataType.DateTime)
                    {
                        //sb.Append("x.DateFieldFor(m => m." + property.Name + ").ColumnWidth(.5).Padding(4),");
                    }
                    else if (dataType.DataType == DataType.Time)
                    {
                        //sb.Append("x.TimeFieldFor(m => m." + property.Name + ").ColumnWidth(.5).Padding(4),");
                    }
                    else if (dataType.DataType == DataType.MultilineText)
                    {
                        sb.AppendLine("<div class=\"form-group\">");
                        sb.Append("@Html.LabelFor(m => m." + property.Name +
                                  ", new { @class = \"col-sm-2 control-label\" })");
                        sb.AppendLine("<div class=\"col-sm-10\">");
                        sb.Append("@Html.Bootstrap().TextareaFor(m => m." + property.Name + ")");
                        sb.Append("</div>");
                        sb.AppendLine("</div>");
                    }
                }
                else if (customAttributes.Any(x => x is HiddenInputAttribute))
                {
                    sb.AppendLine("@Html.HiddenFor(x => x." + property.Name + ")");
                }
                else if (customAttributes.Any(x => x is CustomFieldAttribute))
                {
                    //var customField = (CustomFieldAttribute)customAttributes.First(x => x is CustomFieldAttribute);
                    //if (customField.FieldType == FieldType.OrgList)
                    //{
                    //    sb.Append("x.DropDownFieldFor(m => m." + property.Name + ").OrgList(Model.OrgTree,\"" + customField.ValueHiddenName + "\").Editable(false).ColumnWidth(.5).Padding(4),");
                    //    sb.AppendFormat("x.HiddenFor(f=>f.{0}),", customField.ValueHiddenName);
                    //}
                }
                else
                {
                    sb.AppendLine("<div class=\"form-group\">");
                    sb.Append("@Html.LabelFor(m => m." + property.Name + ", new { @class = \"col-sm-2 control-label\" })");
                    sb.AppendLine("<div class=\"col-sm-10\">");
                    sb.Append("@Html.Bootstrap().TextBoxFor(m => m." + property.Name + ")");
                    sb.Append("</div>");
                    sb.AppendLine("</div>");
                }
                fieldInserted = true;
            }

            if (fieldInserted)
            {
                sb.Remove(sb.Length - 1, 1);
            }
            sb.AppendLine();
        }
        private void RendingReading(StringBuilder sb, object model) { }
        #endregion

        //用来缓存模型定义
        private readonly Dictionary<Type, Dictionary<string, ColumnAttribute>> _columnInfos =
            new Dictionary<Type, Dictionary<string, ColumnAttribute>>();
        /// <summary>
        /// 获取模型的列定义
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private Dictionary<string, ColumnAttribute> GetColumnInfos(object model)
        {
            if (_columnInfos.ContainsKey(model.GetType()))
            {
                return _columnInfos[model.GetType()];
            }
            else
            {
                _columnInfos.Add(model.GetType(), new Dictionary<string, ColumnAttribute>());
            }
            foreach (var property in model.GetType().GetProperties())
            {
                var column =
                    property.GetCustomAttributes(typeof(ColumnAttribute), false).FirstOrDefault() as ColumnAttribute;
                if (column == null) continue;

                _columnInfos[model.GetType()].Add(property.Name, column);
            }

            _columnInfos[model.GetType()] = _columnInfos[model.GetType()].OrderBy(x => x.Value.Order)//.ThenByDescending(x => x.Key)
                .ToDictionary(k => k.Key, v => v.Value);

            return _columnInfos[model.GetType()];
        }
    }
}